﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;

namespace NetTopologySuite.Shape.Fractal
{
	public class SierpinskiCarpetBuilder : GeometricShapeBuilder
	{
		public SierpinskiCarpetBuilder(IGeometryFactory geomFactory) : base(geomFactory)
		{
		}

		private static int RecursionLevelForSize(int numPts)
		{
			return (int)(Math.Log((double)numPts / 3.0) / Math.Log(4.0));
		}

		public override IGeometry GetGeometry()
		{
			int n = SierpinskiCarpetBuilder.RecursionLevelForSize(base.NumPoints);
			Coordinate coordinate = base.GetSquareBaseLine().GetCoordinate(0);
			ILinearRing[] holes = this.GetHoles(n, coordinate.X, coordinate.Y, base.Diameter);
			ILinearRing shell = (ILinearRing)((IPolygon)this.GeomFactory.ToGeometry(base.GetSquareExtent())).ExteriorRing;
			return this.GeomFactory.CreatePolygon(shell, holes);
		}

		private ILinearRing[] GetHoles(int n, double originX, double originY, double width)
		{
			List<IGeometry> list = new List<IGeometry>();
			this.AddHoles(n, originX, originY, width, list);
			return GeometryFactory.ToLinearRingArray(list);
		}

		private void AddHoles(int n, double originX, double originY, double width, ICollection<IGeometry> holeList)
		{
			if (n < 0)
			{
				return;
			}
			int n2 = n - 1;
			double num = width / 3.0;
			this.AddHoles(n2, originX, originY, num, holeList);
			this.AddHoles(n2, originX + num, originY, num, holeList);
			this.AddHoles(n2, originX + 2.0 * num, originY, num, holeList);
			this.AddHoles(n2, originX, originY + num, num, holeList);
			this.AddHoles(n2, originX + 2.0 * num, originY + num, num, holeList);
			this.AddHoles(n2, originX, originY + 2.0 * num, num, holeList);
			this.AddHoles(n2, originX + num, originY + 2.0 * num, num, holeList);
			this.AddHoles(n2, originX + 2.0 * num, originY + 2.0 * num, num, holeList);
			holeList.Add(this.CreateSquareHole(originX + num, originY + num, num));
		}

		private ILinearRing CreateSquareHole(double x, double y, double width)
		{
			Coordinate[] coordinates = new Coordinate[]
			{
				new Coordinate(x, y),
				new Coordinate(x + width, y),
				new Coordinate(x + width, y + width),
				new Coordinate(x, y + width),
				new Coordinate(x, y)
			};
			return this.GeomFactory.CreateLinearRing(coordinates);
		}
	}
}
